package net.example.manager;


import com.oraycn.esbasic.helpers.StringHelper;
import com.oraycn.esbasic.objectManagement.LimitQueue;
import com.oraycn.esbasic.objectManagement.managers.ObjectManager;
import com.oraycn.esframework.core.ClientType;
import com.oraycn.esframework.core.IRapidPassiveEngine;
import com.oraycn.omcs.utils.BufferUtils;

import net.example.activity.view.sessionview.MessageItem;
import net.example.db.ChatMessageRecordPersister;
import net.example.db.GGGroupPersister;
import net.example.db.GGUserPersister;
import net.example.db.LastChatRecordPersister;
import net.example.model.ChatInfo;
import net.example.model.ContractType;
import net.example.model.GGGroup;
import net.example.model.GGUser;
import net.example.model.GroupChangedType;
import net.example.model.UnitType;
import net.example.model.UserStatus;
import net.example.model.event.NotReadMsgCountChangedEvent;
import net.example.model.event.UnitRequestCountChangedEvent;
import net.example.utils.PinyinComparator;
import net.example.utils.SerializeHelper;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import de.greenrobot.event.EventBus;
import io.netty.buffer.ByteBuf;


public  class ClientGlobalCache {
    private IRapidPassiveEngine engine;
    private GGUser currentUser;
    private int pageSize4LoadFriends = 20;
    private ObjectManager<String, GGUser> userManager = new ObjectManager<String, GGUser>(); //缓存用户资料
    private ObjectManager<String, GGGroup> groupManager = new ObjectManager<String, GGGroup>();
    private ObjectManager<String, LimitQueue<ChatInfo>> chatInfoManager=new ObjectManager<String, LimitQueue<ChatInfo>>();
    private ConcurrentHashMap<String,Integer> notReadMsgMap =new ConcurrentHashMap<>();//未读消息字典
    private List<String> requestAddFriendList=new ArrayList<>();//请求加好友列表
    private List<String> requestAddGroupList=new ArrayList<>();//请求加入讨论组列表
    private IGlobalCacheListener globalCacheListener = new EmptyGlobalCacheListener();
    private ICacheProgressListener cacheProgressListener = new EmptyCacheProgressListener();
    private List<ClientType> myOnlineClientTypes =new ArrayList<>();//我在线的设备
//    public void setGlobalCacheListener(IGlobalCacheListener globalCacheListener) {
//        this.globalCacheListener = globalCacheListener;
//    }

    public void setCacheProgressListener(ICacheProgressListener listener){
        this.cacheProgressListener = listener ;
    }

    private static ClientGlobalCache cache;
    public static ClientGlobalCache getInstance() {
        if (cache == null) {
            cache = new ClientGlobalCache();
        }
        return cache;
    }

    //初始化，从本地DB中加载所有联系人和群组
    public void initialize(IRapidPassiveEngine _engine) {
        this.engine = _engine;
        this.myOnlineClientTypes=this.engine.getBasicOutter().getMyOnlineDevice();
        this.currentUser = this.DoGetUser(this.engine.getCurrentUserID());
        this.currentUser.setUserStatus(UserStatus.Online);
        this.userManager.add(this.currentUser.getUserID(), this.currentUser);
        this.UpdateUserInLocalDB(this.currentUser);
        List<GGUser> users = GGUserPersister.getInstance().getAll();
        for (GGUser user : users) {
            user.setUserStatus(UserStatus.OffLine);
            user.setCommentName(this.currentUser.getUnitCommentName(user.getUserID()));
            this.userManager.add(user.getUserID(), user);
        }

        List<GGGroup> groups = GGGroupPersister.getInstance().getAll();
        String[] groupAry = this.currentUser.getGroups().split(",");
        List<String> groupList = Arrays.asList(groupAry);
        for (GGGroup group : groups) {
            if(groupList.contains(group.getGroupID())) {
                this.groupManager.add(group.getGroupID(), group);
            }
        }
    }

    public IRapidPassiveEngine getRapidPassiveEngine(){
        return this.engine;
    }

    private void updateChatInfo(String talkingID, ChatInfo chatInfo)
    {
        LimitQueue<ChatInfo> queue= this.chatInfoManager.get(talkingID);
        if(queue==null)
        {
            return;
        }
        ChatInfo[] infos=new ChatInfo[queue.size()];
        queue.toArray(infos);
        for (ChatInfo info :infos) {
            if(chatInfo.getAutoID()==info.getAutoID())
            {
                info=chatInfo;
                break;
            }
        }
    }


    public LimitQueue<ChatInfo> getChatInfos(String talkingID)
    {
        if(!openChatPageUserIDList.contains(talkingID))
        {
            openChatPageUserIDList.add(talkingID);
        }
        return this.chatInfoManager.get(talkingID);
    }
    //打开过聊天框的用户ID（包括组ID）
    private List<String> openChatPageUserIDList=new ArrayList<>();

    public void addChatInfos(String talkingID, Collection<ChatInfo> chatInfos)
    {
        if(!openChatPageUserIDList.contains(talkingID))
        {
            return;
        }
        LimitQueue<ChatInfo> queue=null;
        if(!this.chatInfoManager.containsKey(talkingID))
        {
            queue=new LimitQueue<ChatInfo>(10);
            this.chatInfoManager.add(talkingID,queue);
        }
        queue=this.chatInfoManager.get(talkingID);
        for(ChatInfo info:chatInfos)
        {
            queue.offer(info);
        }
    }

    private void addChatInfos(String talkingID, ChatInfo chatInfo)
    {
        if(!openChatPageUserIDList.contains(talkingID))
        {
            return;
        }
        LimitQueue<ChatInfo> queue=null;
        if(!this.chatInfoManager.containsKey(talkingID))
        {
            queue=new LimitQueue<ChatInfo>(10);
            this.chatInfoManager.add(talkingID,queue);
        }
        queue=this.chatInfoManager.get(talkingID);
        queue.offer(chatInfo);
    }

    private final Object addFriendlocker=new Object();
    public void addRequestAddFriend(String friendID)
    {
        if(this.requestAddFriendList.contains(friendID))
        {
            return;
        }
        synchronized(addFriendlocker)
        {
            this.requestAddFriendList.add(friendID);
            EventBus.getDefault().post(new UnitRequestCountChangedEvent(UnitType.User,this.requestAddFriendList.size()));
        }

    }

    public void removeRequestAddFriend(String friendID)
    {
        if(!this.requestAddFriendList.contains(friendID))
        {
            return;
        }
        synchronized(addFriendlocker)
        {
            this.requestAddFriendList.remove(friendID);
            EventBus.getDefault().post(new UnitRequestCountChangedEvent(UnitType.User, this.requestAddFriendList.size()));
        }

    }

    public GGUser getRequestAddFriend(String friendID)
    {
       if(!this.requestAddFriendList.contains(friendID))
       {
           return null;
       }
       return this.userManager.get(friendID);
    }

    public int getRequestAddFriendCount()
    {
        return this.requestAddFriendList.size();
    }

    private final Object addGrouplocker=new Object();
    public void addRequestAddGroup(String requesterID,String groupID)
    {
        String key = requesterID + "-" + groupID;
        if (this.requestAddGroupList.contains(key)) {
            return;
        }
        synchronized(addFriendlocker)
        {
            this.requestAddGroupList.add(key);
            EventBus.getDefault().post(new UnitRequestCountChangedEvent(UnitType.Group, this.requestAddGroupList.size()));
        }

    }

    public void removeRequestAddGroup(String requesterID,String groupID)
    {
        String key = requesterID + "-" + groupID;
        if (!this.requestAddGroupList.contains(key)) {
            return;
        }
        synchronized(addFriendlocker){
            this.requestAddGroupList.remove(key);
            EventBus.getDefault().post(new UnitRequestCountChangedEvent(UnitType.Group, this.requestAddGroupList.size()));
        }
    }

    public int getRequestAddGroupCount() {
        return this.requestAddGroupList.size();
    }

    /**
     * 初始化未读消息Map
     * */
    public void initNotReadMsgMap()
    {
        List<MessageItem> list = LastChatRecordPersister.getInstance().getMyLastMessageRecord();
        if(list!=null&&list.size()>0)
        {
            int unReadCount=0;
            for (MessageItem item :list) {
                unReadCount+=item.unReadCount;
                if(item.unReadCount>0)
                {
                    notReadMsgMap.put(item.senderID,item.unReadCount);
                }
            }
            if(unReadCount>0)
            {
                EventBus.getDefault().post(new NotReadMsgCountChangedEvent(unReadCount));
            }
        }
    }

    //添加对象未读消息数
    public void addNotReadMsg(String target)
    {
        int notReadCount=0;
        if(notReadMsgMap.containsKey(target))
        {
            notReadCount= notReadMsgMap.get(target);
        }
        ++notReadCount;
        notReadMsgMap.put(target,notReadCount);
        EventBus.getDefault().post(new NotReadMsgCountChangedEvent(this.getTotalNotReadMsgCount()));
    }

    //移除对象未读消息
    public void removeNotReadMsg(String target)
    {
        if(!notReadMsgMap.containsKey(target))
        {
            return;
        }
        notReadMsgMap.remove(target);
        EventBus.getDefault().post(new NotReadMsgCountChangedEvent(this.getTotalNotReadMsgCount()));
    }


    public int getTotalNotReadMsgCount()
    {
        if(notReadMsgMap.size()==0)
        {
            return 0;
        }
        int totalCount=0;
        for (int itemCount : notReadMsgMap.values()) {
            totalCount+=itemCount;
        }
        return totalCount;
    }

    //调用完initialize方法后，调用此方法以判断当前用户是否是第一次登录到该手机（没有任何缓存数据）。
    public boolean isNewLoginUser() {
        return this.userManager.size() <= 1;
    }

    //同步服务器最新的联系人和群组资料
    public void startRefreshFriendInfo() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                if (userManager.size() == 1) {
                    loadContactsFromServer();
                } else {
                    refreshContactRTData();
                }
            }
        });
    }

    //同步服务器最新的联系人和群组资料
    public void refreshFriendInfo() {
        if (userManager.size() == 1) {
            loadContactsFromServer();
        } else {
            refreshContactRTData();
        }
    }

    public void reLoadCurrentUserFromServer(){
        GGUser user = this.DoGetUser(this.currentUser.getUserID());
        updateUser(user);
    }

    public void reSetGroupCache()
    {
        this.setGroupCacheByServer();
    }

    public GGUser getCurrentUser() {
        return this.currentUser;
    }

    public GGUser getUser4Cache(String userID)
    {
        return this.userManager.get(userID);
    }
    public GGUser getUser(String userID) {
         GGUser user=null;
         if(this.currentUser.getUserID().equals(userID))
         {
             return this.currentUser;
//             user= this.DoGetUser(userID);
//             updateUser(user);
         }else {
             user= this.userManager.get(userID);
         }
         if(user==null)
         {
             user=this.DoGetUser(userID);
             if(user!=null)
             {
                 this.userManager.add(userID,user);
             }
         }
         return user;
    }

    /**
     * 获取用户名称
     * */
    public String getUserName(String userID)
    {
        GGUser GGUser = this.getUser(userID);
        if(GGUser ==null){return "";}
        return GGUser.getCommentName();
    }


    /**
     * 从内存中查询用户
     * */
    public List<GGUser> SearchUser(String idOrName){
        List<GGUser> list = new ArrayList<GGUser>();
        for(GGUser user : this.userManager.getAll())
        {
            if (user.getUserID().equals(idOrName) || user.getName().equals(idOrName)||user.getCommentName().equals(idOrName))
            {
                list.add(0,user);
                continue;
            }
            if(user.getUserID().contains(idOrName)||user.getName().contains(idOrName)||user.getCommentName().equals(idOrName))
            {
                list.add(user);
            }
        }
        return list;
    }
    /**
     * 根据UserID或名称本地模糊查询 (若存在有一个完全匹配就单独返回该用户，否则返回匹配该字符且是好友的所有用户)
     * */
    public List<GGUser> searchUserFuzzy(String userID)
    {
        List<GGUser> list = new ArrayList<GGUser>();
        if(StringHelper.isNullOrEmpty(userID))
        {
            return list;
        }
        List<GGUser> users=  this.userManager.getAll();
        for (GGUser user:  users) {
            if(user.getUserID().equals(userID))
            {
                list.add(user);
                return list;
            }
        }
        for(GGUser user : users)
        {
            if(user.getUserID().contains(userID)||user.getCommentName().contains(userID)||user.getName().contains(userID))
            {
                list.add(user);
            }
        }
        return list;
    }

    /**
     * 根据groupID或名称本地模糊查询  (若存在有一个完全匹配就单独返回该组，否则返回匹配该字符且是好友的所有用户)
     * */
    public List<GGGroup> searchGroupFuzzy(String groupID)
    {
        List<GGGroup> list = new ArrayList<GGGroup>();
        if(StringHelper.isNullOrEmpty(groupID))
        {
            return list;
        }
        List<GGGroup> groups=this.groupManager.getAll();
        for (GGGroup group:  groups) {
            if(group.getGroupID().equals(groupID))
            {
                list.add(group);
                return list;
            }
        }
        for(GGGroup group : this.groupManager.getAll())
        {
            if(group.getGroupID().contains(groupID)||group.getName().contains(groupID))
            {
                list.add(group);
            }
        }
        return list;
    }

    public List<GGUser> getGGUserList(Collection<String> userIDList)
    {
        if(userIDList==null)
        {
            return null;
        }
        ArrayList<GGUser> GGUsers =new ArrayList<GGUser>();
        for (String userID:userIDList) {
            GGUser GGUser =this.getUser(userID);
            if(GGUser ==null)
            {
                continue;
            }
            GGUsers.add(GGUser);
        }
        Collections.sort(GGUsers, new Comparator<GGUser>() {
            @Override
            public int compare(GGUser x, GGUser y) {
                return PinyinComparator.compare(x.getName(),y.getName());
            }
        });
        return GGUsers;
    }

    public boolean isUserExist(String userID){
        return this.userManager.containsKey(userID);
    }

    public void updateUser(GGUser user)
    {
        if(this.userManager.containsKey(user.getUserID())){
            user.setCommentName(this.currentUser.getUnitCommentName(user.getUserID()));
            GGUser oldUser= this.userManager.get(user.getUserID());
            oldUser=user;
            if(this.currentUser.getUserID().equals(user.getUserID()))
            {
                this.currentUser=user;
            }
        }
    }

    /**
     * 是否为好友
     * */
    public Boolean isFriend(String friendID) {
        HashMap<String, ArrayList<String>> friendMap = this.currentUser.getFriendMap();
        for (ArrayList<String> firendIDs : friendMap.values()) {
            if (firendIDs.contains(friendID)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 是否为黑名单用户
     * */
    public Boolean isBlackListUser(String friendID)
    {
        HashMap<String, ArrayList<String>> friendMap = this.currentUser.getFriendMap();
        List<String> blackList= friendMap.get("黑名单");
        return blackList.contains(friendID);
    }

    /// <summary>
    /// 当自己的基础资料发生变化时，也请调用此方法。（将触发 MyBaseInfoChanged 或 UserBaseInfoChanged 事件）
    /// </summary>
    public void updateUserBaseInfo(String userID, String name, String signature, String orgID, int userLatestVersion)
    {
        if (this.currentUser.getUserID() == userID)
        {
            this.currentUser.setName(name);
            this.currentUser.setSignature(signature);
            this.currentUser.setOrgID(orgID);
            this.currentUser.setVersion(userLatestVersion);
            this.updateUser(this.currentUser);
        }
        else
        {
            GGUser user = this.userManager.get(userID);
            if (user != null)
            {
                user.setName(name);
                user.setSignature(signature);
                user.setOrgID(orgID);
                user.setVersion(userLatestVersion);
            }
        }
    }


    public GGGroup getGroup(String groupID) {
        GGGroup group = this.groupManager.get(groupID);
        if (group == null)
        {
            group = this.DoGetGroup(groupID);
            if (group != null)
            {
                //group.CommentName = this.currentUser.GetUnitCommentName(group.ID);
                this.groupManager.add(group.getGroupID(), group);
            }
        }

        return group;
    }

    public boolean isGroupExist(String groupID){
        return this.groupManager.containsKey(groupID);
    }

    public Collection<GGGroup> getGroups() {
        return this.groupManager.getAll();
    }

    public void removeGroup(String groupID) {
        if(this.groupManager.containsKey(groupID))
        {
            this.currentUser.removeGroup(groupID);
            this.groupManager.remove(groupID);
        }
        GGGroupPersister.getInstance().delete(groupID);
    }

    public void updateGroupBaseInfo(String groupID,String groupName,String announce)
    {
       GGGroup group=  this.groupManager.get(groupID);
       if(group==null)
       {
           return;
       }
       group.setName(groupName);
       group.setAnnounce(announce);
    }

    public void OnCreateOrUpdateGroup(GGGroup group)
    {
        this.currentUser.addGroup(group.getGroupID());
        this.groupManager.add(group.getGroupID(), group);
        UpdateGroupInLocalDB(group);
    }

    public void resetSomeGroups(List<String> groupIDs)
    {
        this.setSomeGroups(groupIDs);
    }

    public void onSomeoneQuitGroup(String groupID, String userID)
    {
        GGGroup group= this.groupManager.get(groupID);
        if(group==null)
        {
            return;
        }
        if (userID == this.currentUser.getUserID())//20210427 新加
        {
            this.globalCacheListener.GroupChanged(group, GroupChangedType.GroupDeleted, userID, null);
            this.groupManager.remove(groupID);
            return;
        }
        List<String> members=new ArrayList<String>(){};
        members.add(userID);
        group.removeMembers(members);
    }

    public void onSomeoneJoinGroup(String groupID,String userID)
    {
        GGGroup group= this.groupManager.get(groupID);
        if(group==null)
        {
            return;
        }
        List<String> members=new ArrayList<String>(){};
        members.add(userID);
        group.addMembers(members);
    }


    public void OnUsersPulledIntoGroup(String groupID, String operatorID, List<String> guests) {
        GGGroup group = this.groupManager.get(groupID);
        if(group != null){
            group.addMembers(guests);
        }
    }

    public void OnUsersRemoveOutGroup(String groupID,String operatorID,List<String> guests)
    {
        GGGroup group = this.groupManager.get(groupID);
        if(group != null){
            group.removeMembers(guests);
        }
    }

    public void addUser(GGUser user){
        if(!this.userManager.containsKey(user.getUserID())){
            user.setCommentName(this.currentUser.getUnitCommentName(user.getUserID()));
            this.userManager.add(user.getUserID(),user);
            GGUserPersister.getInstance().insert(user);
            if(user.getUserID().equals(this.currentUser.getUserID()))
            {
                this.currentUser=user;
            }
        }
    }

    public List<GGUser> getUserByOrgID(String orgID) {
        List<GGUser> returnList = new ArrayList();
        for (GGUser user : this.userManager.getAll()) {
            if (user.getOrgID().equals(orgID)) {
                user.setCommentName(this.currentUser.getUnitCommentName(user.getUserID()));
                returnList.add(user);
            }
        }
        return returnList;
    }


    /**
     * 获取在线用户数量 （不包括离线和隐身的）
     * @return
     */
    public int getOnlineUserCount()
    {
        int online = 0;
        for (GGUser user :this.userManager.getAll()) {
            if(user.getUserStatus()!=UserStatus.OffLine && user.getUserStatus() != UserStatus.Hide)
            {
                ++online;
            }
        }
        return online;
    }

    public String getOnlineUserCountScale(){
        return String.format("(%d/%d)",this.getOnlineUserCount(),this.userManager.size());
    }


    public void onChangeUnitCommentName(String userID,String commentName)
    {
       GGUser user=  this.userManager.get(userID);
       if(user==null)
       {
           return;
       }
       user.setCommentName(commentName);
       this.currentUser.changeUnitCommentName(userID, commentName);
    }

    //接收到服务端通知时，更新缓存
    public void onUserStatusChanged(String userID, UserStatus newStatus) {
        GGUser user = this.userManager.get(userID);
        if (user != null) {
            user.setUserStatus(newStatus);
        }
    }

    //从服务器加载所有的联系人和群组资料
    private void loadContactsFromServer() {
        try {
            this.globalCacheListener.BatchLoadStarted();
            List<String> allContactList = this.DoGetAllContactIDs();
            this.cacheProgressListener.LoadedProcess(allContactList.size() ,0);
            int pageCount = allContactList.size() / this.pageSize4LoadFriends;
            int lastPageSize = allContactList.size() % this.pageSize4LoadFriends;
            if (lastPageSize > 0) {
                pageCount += 1;
            } else {
                lastPageSize = this.pageSize4LoadFriends;
            }

            if (pageCount == 1) {
                //好友，包括组友
                List<GGUser> friends = this.DoGetAllContacts();
                for (GGUser friend : friends) {
                    if (friend.getUserID() != this.currentUser.getUserID()) {
                        friend.setCommentName(this.currentUser.getUnitCommentName(friend.getUserID()));
                        this.userManager.add(friend.getUserID(), friend);
                        this.UpdateUserInLocalDB(friend);
                        this.globalCacheListener.UserBaseInfoChanged(friend);
                    }
                }
            } else {
                int loadedCount = 0;
                for (int i = 0; i < pageCount; i++) {
                    int count = (i == pageCount - 1) ? lastPageSize : this.pageSize4LoadFriends;
                    List<String> tmp = new ArrayList<String>();
                    for (int j = 0; j < count; j++) {
                        tmp.add(allContactList.get(i * this.pageSize4LoadFriends + j));
                    }

                    List<GGUser> friends = this.DoGetSomeUsers(tmp);
                    for (GGUser friend : friends) {
                        if (friend.getUserID() != this.currentUser.getUserID()) {
                            friend.setCommentName(this.currentUser.getUnitCommentName(friend.getUserID()));
                            this.userManager.add(friend.getUserID(), friend);
                            this.UpdateUserInLocalDB(friend);
                            this.globalCacheListener.UserBaseInfoChanged(friend);
                        }
                    }
                    loadedCount += friends.size();
                    this.cacheProgressListener.LoadedProcess(allContactList.size(),loadedCount);
                }
            }
            this.cacheProgressListener.LoadedProcess(allContactList.size() ,allContactList.size());
            this.setGroupCacheByServer();

        } catch (Exception ee) {
            ee.printStackTrace();
        }

        this.globalCacheListener.BatchLoadCompleted();
    }

    private void setGroupCacheByServer()
    {
        List<GGGroup> myGroups = this.DoGetMyGroups();
        for (GGGroup group : myGroups) {
            this.groupManager.add(group.getGroupID(), group);
        }

        for (GGGroup group : myGroups) {
            this.UpdateGroupInLocalDB(group);
            this.globalCacheListener.GroupChanged(group, GroupChangedType.GroupInfoChanged, null, null);
        }
    }

    private void refreshContactRTData() {
        try {
            this.globalCacheListener.BatchLoadStarted();
            ContactRTDatas contract = this.DoGetContactsRTDatas(); //1000用户数据量大小为22k

            if(userManager!=null) {
                for (String userID : this.userManager.getKeyList()) {
                    if (!userID.equals(this.currentUser.getUserID()) && !contract.UserStatusDictionary.containsKey(userID)) //最新的联系人中不包含缓存用户，则将之从缓存中删除。
                    {
                        this.userManager.remove(userID);
                        GGUserPersister.getInstance().delete(userID);
                        this.globalCacheListener.FriendRemoved(userID);
                    }
                }
            }

            int loadedCount = 0 ;
            for (Map.Entry<String, UserRTData> pair : contract.UserStatusDictionary.entrySet()) {
                ++loadedCount ;
                this.cacheProgressListener.LoadedProcess(contract.UserStatusDictionary.size(),loadedCount);
                if (pair.getKey().equals(this.currentUser.getUserID()) ) {
                    continue;
                }
                GGUser origin = this.userManager.get(pair.getKey());
                if (origin == null)  //不存在于本地缓存中
                {
                    GGUser user = this.DoGetUser(pair.getKey());
                    user.setCommentName(this.currentUser.getUnitCommentName(user.getUserID()));
                    this.userManager.add(user.getUserID(), user);
                    this.UpdateUserInLocalDB(user);
                    this.globalCacheListener.UserBaseInfoChanged(user);
                } else {
                    //资料变化
                    if (pair.getValue().Version != origin.getVersion()) {
                        GGUser user = this.DoGetUser(pair.getKey());
                        user.setCommentName(this.currentUser.getUnitCommentName(user.getUserID()));
                        user.setLastWordsRecord(origin.getLastWordsRecord());
                        //user.ReplaceOldUnit(origin);
                        this.userManager.add(user.getUserID(), user);
                        this.UpdateUserInLocalDB(user);
                        this.globalCacheListener.UserBaseInfoChanged(user);
                    } else {
                        //状态变化
                        if (origin.getUserStatus() != pair.getValue().Status) {
                            origin.setUserStatus(pair.getValue().Status);
                            this.globalCacheListener.UserStatusChanged(origin);
                        }
                    }
                }
            }
            this.cacheProgressListener.LoadedProcess(contract.UserStatusDictionary.size(),contract.UserStatusDictionary.size());

            List<String> updateGroupList = new ArrayList<String>();
            for (String groupID : this.currentUser.getGroups().split(",")) {
                if(StringHelper.isNullOrEmpty(groupID)){
                    continue;
                }
                GGGroup group = this.groupManager.get(groupID);
                if (group == null) {
                    updateGroupList.add(groupID);
                    continue;
                }

                if (contract.GroupVersionDictionary.containsKey(groupID)) {
                    if (contract.GroupVersionDictionary.get(groupID).intValue() != group.getVersion()) {
                        updateGroupList.add(groupID);
                        continue;
                    }
                }
            }
            if (updateGroupList.size() > 0) {
                    this.setSomeGroups(updateGroupList);
                }
        } catch (Exception ee) {
            ee.printStackTrace();
        }
        this.globalCacheListener.BatchLoadCompleted();
    }

    //从服务端获取并更新某些讨论组缓存
    private void setSomeGroups(List<String> updateGroupList)
    {
        //加载组
        List<GGGroup> newGroups = this.DoGetSomeGroups(updateGroupList);
        for (GGGroup group : newGroups) {
            this.currentUser.addGroup(group.getGroupID());
            //group.setCommentName(this.currentUser.GetUnitCommentName(group.getGroupID()));
            GGGroup old = this.groupManager.get(group.getGroupID());
            if (old != null) {
                group.setLastWordsRecord(old.getLastWordsRecord());
                //group.ReplaceOldUnit(old);
            }
            this.groupManager.add(group.getGroupID(), group);
            this.UpdateGroupInLocalDB(group);
            this.globalCacheListener.GroupChanged(group, GroupChangedType.GroupInfoChanged, null, null);
        }
    }

    public GGUser DoGetUser(String userID) {
        GGUser GGUser = null;
        try {
            byte[] returnValue = this.engine.getCustomizeOutter().query(ContractType.GetUserInfo.getType(), userID.getBytes(StandardCharsets.UTF_8));
            if (returnValue != null && returnValue.length > 4) {
                GGUser = new GGUser();
                GGUser.deserialize(returnValue);
            }
        } catch (Exception ee) {
            ee.printStackTrace();
        }

        return GGUser;
    }

    private List<GGGroup> DoGetMyGroups() {
        try {
            byte[] groupBytes = this.engine.getCustomizeOutter().query(ContractType.GetMyGroups.getType(), null);
            return GGGroup.deserializeGroupList(groupBytes);
        } catch (Exception ee) {
            ee.printStackTrace();
        }
        return new ArrayList<>();
    }

    private List<GGGroup> DoGetSomeGroups(List<String> groupIDList) {
        try {
            ByteBuf buff = SerializeHelper.newBuffer();
            buff.writeInt(groupIDList.size());
            for (int i = 0; i < groupIDList.size(); i++) {
                byte[] txt = groupIDList.get(i).getBytes(StandardCharsets.UTF_8);
                buff.writeInt(txt.length);
                buff.writeBytes(txt);
            }
            byte[] groupBytes = this.engine.getCustomizeOutter().query(ContractType.GetSomeGroups.getType(), buff.array());
            return GGGroup.deserializeGroupList(groupBytes);
        } catch (Exception ee) {
            ee.printStackTrace();
        }
        return new ArrayList<>();
    }

    private GGGroup DoGetGroup(String groupID) {
        try {

            byte[] txt =groupID.getBytes(StandardCharsets.UTF_8);

            byte[] groupBytes = this.engine.getCustomizeOutter().query(ContractType.GetGroup.getType(), txt);
            GGGroup group = new GGGroup();
            group.deserialize(groupBytes);
            return  group ;
        } catch (Exception ee) {
            ee.printStackTrace();
        }
        return null;
    }

    private ContactRTDatas DoGetContactsRTDatas() {
        try {
            byte[] bytes = this.engine.getCustomizeOutter().query(ContractType.GetContactsRTData.getType(), null);
            return ContactRTDatas.deserialize(SerializeHelper.wrappedBuffer(bytes));
        } catch (Exception ee) {
            ee.printStackTrace();
        }
        return new ContactRTDatas();
    }

    private List<GGUser> DoGetSomeUsers(List<String> userIDList) {
        try {
            ByteBuf buff = SerializeHelper.newBuffer();
            buff.writeInt(userIDList.size());
            for (int i = 0; i < userIDList.size(); i++) {
                byte[] txt = userIDList.get(i).getBytes(StandardCharsets.UTF_8);
                buff.writeInt(txt.length);
                buff.writeBytes(txt);
            }
            byte[] bUsers = this.engine.getCustomizeOutter().query(ContractType.GetSomeUsers.getType(), buff.array());
            return GGUser.deserializeUserList(bUsers);
        } catch (Exception ee) {
            ee.printStackTrace();
        }
        return new ArrayList<>();
    }

    private List<GGUser> DoGetAllContacts() {
        try {
            byte[] bUsers = this.engine.getCustomizeOutter().query(ContractType.GetAllContacts.getType(), null);
            return GGUser.deserializeUserList(bUsers);
        } catch (Exception ee) {
            ee.printStackTrace();
        }
        return new ArrayList<>();
    }

    private List<String> DoGetAllContactIDs() {
        List<String> list = new ArrayList<>();
        try {
            byte[] bytes = this.engine.getCustomizeOutter().query(ContractType.GetAllContactIDs.getType(), null);
            ByteBuf buf = SerializeHelper.wrappedBuffer(bytes);
            int count = buf.readInt();
            for (int i = 0; i < count; i++) {
                int len = buf.readInt();
                byte[] txt = new byte[len];
                buf.readBytes(txt);
                list.add(new String(txt, StandardCharsets.UTF_8));
            }
            return list;
        } catch (Exception ee) {
            ee.printStackTrace();
        }
        return list;
    }

    public void UpdateUserInLocalDB(GGUser user) {
        GGUserPersister.getInstance().delete(user.getUserID());
        GGUserPersister.getInstance().insert(user);
    }

    public void UpdateGroupInLocalDB(GGGroup group) {
        GGGroupPersister.getInstance().delete(group.getGroupID());
        GGGroupPersister.getInstance().insert(group);
    }
    
    public void InsertChatMessageRecordInLocalDB(String talkingID, ChatInfo chatInfo)
    {
        long autoID = ChatMessageRecordPersister.getInstance().insert(chatInfo);
        chatInfo.setAutoID(autoID);        
        this.addChatInfos(talkingID,chatInfo);
    }
    
    public void UpdateChatMessageRecordInLocalDB(String talkingID,ChatInfo chatInfo)
    {
        ChatMessageRecordPersister.getInstance().update(chatInfo);
        this.updateChatInfo(talkingID,chatInfo);
    }

    public void DeleteChatMessageRecordInLocalDB(String talkingID,boolean isGroupChat)
    {
        ChatMessageRecordPersister.getInstance().delete(talkingID,isGroupChat);
        this.chatInfoManager.remove(talkingID);
    }

    public void DeleteChatMessageRecordInLocalDB(String talkingID,long autoID)
    {
        ChatMessageRecordPersister.getInstance().delete(autoID);
        LimitQueue<ChatInfo> chatInfos=  this.chatInfoManager.get(talkingID);
        for (ChatInfo chatInfo :chatInfos) {
            if(chatInfo.getAutoID()==autoID)
            {
                chatInfos.remove(chatInfo);
                break;
            }
        }
    }

    public void DeleteChatMessageRecordInLocalDB4SnapchatMessageID(String talkingID, String snapchatMessageID)
    {
        if(StringHelper.isNullOrEmpty(snapchatMessageID))
        {
            return;
        }
        ChatMessageRecordPersister.getInstance().delete4SnapchatMessageID(snapchatMessageID);
        LimitQueue<ChatInfo> chatInfos=  this.chatInfoManager.get(talkingID);
        for (ChatInfo chatInfo :chatInfos) {
            if(chatInfo.snapchatMessageID.equals(snapchatMessageID))
            {
                chatInfos.remove(chatInfo);
                break;
            }
        }
    }

    public void clearCache()
    {
        this.userManager.clear();
        this.groupManager.clear();
        this.chatInfoManager.clear();
        this.requestAddFriendList.clear();
    }

    /**
     * 自己账号在其他客户端上线,添加直接的在线客户端类型
     * */
    public void addOnlineClientType(ClientType clientType)
    {
        if(this.myOnlineClientTypes==null)
        {
            return;
        }
        if(!this.myOnlineClientTypes.contains(clientType))
        {
            this.myOnlineClientTypes.add(clientType);
        }
    }

    /**
     * 自己账号在其他客户端下线。移除直接的在线客户端类型
     * */
    public void removeOnlineClientType(ClientType clientType)
    {
        if(this.myOnlineClientTypes==null)
        {
            return;
        }
        this.myOnlineClientTypes.remove(clientType);
    }

    /**
     * 自己账号在是否在PC端登陆
     * */
    public boolean getMyOnlineClientTypeContainsPC()
    {
        return this.myOnlineClientTypes.contains(ClientType.DOT_NET);
    }
}

interface IGlobalCacheListener {
    void BatchLoadStarted() ;
    void BatchLoadCompleted();
    void UserBaseInfoChanged(GGUser user) ;
    void UserStatusChanged(GGUser user) ;
    void GroupChanged(GGGroup group, GroupChangedType type, String operatorID, String target);//group - type - operatorID - target
    void FriendRemoved(String friendID);
}

class EmptyCacheProgressListener implements ICacheProgressListener{
    public void LoadedProcess(int total, int val){}
}

class EmptyGlobalCacheListener implements IGlobalCacheListener
{

    @Override
    public void BatchLoadStarted() {

    }

    @Override
    public void BatchLoadCompleted() {

    }

    @Override
    public void UserBaseInfoChanged(GGUser user) {

    }

    @Override
    public void UserStatusChanged(GGUser user) {

    }

    @Override
    public void GroupChanged(GGGroup group, GroupChangedType type, String operatorID, String target) {

    }

    @Override
    public void FriendRemoved(String friendID) {

    }
}

class UserRTData {
    public UserStatus Status ;
    public int Version ;

    public static UserRTData deserialize(ByteBuf buf)
    {
        UserRTData data = new UserRTData() ;
        buf.readInt();
        data.Status =  UserStatus.getUserStatusByCode(buf.readInt());
        data.Version =  buf.readInt();
        return  data ;
    }
}
class ContactRTDatas {
    public HashMap<String, UserRTData> UserStatusDictionary = new HashMap<String, UserRTData>();
    public HashMap<String, Integer> GroupVersionDictionary = new HashMap<String, Integer>();

    public static ContactRTDatas deserialize(ByteBuf buf) {
        ContactRTDatas datas = new ContactRTDatas();
        try {
            buf.readInt();
            int gvCount = buf.readInt();
            for (int i = 0; i < gvCount; i++) {
                String groupID = SerializeHelper.readStrIntLen(buf);
                int ver = buf.readInt();
                datas.GroupVersionDictionary.put(groupID, new Integer(ver));
            }

            int statusCount = buf.readInt();
            for (int i = 0; i < statusCount; i++) {
                String userID = SerializeHelper.readStrIntLen(buf);
                UserRTData rtData = UserRTData.deserialize(buf);
                datas.UserStatusDictionary.put(userID, rtData);
            }

            return datas;
        } catch (Exception ee) {
            ee.printStackTrace();
        }
        return null;
    }
}
